﻿using System.Linq;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace System.Web.Mvc
{
	public static partial class Holovacs
	{

		public static HtmlString EnumSelectListFor<TModel, TProperty>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> forExpression,
			object htmlAttributes,
			bool blankFirstLine)
			where TModel : class
			where TProperty : struct
		{
			//MS, it its infinite wisdom, does not allow enums as a generic constraint, so we have to check here.
			if (!typeof(TProperty).IsEnum) throw new ArgumentException("This helper method requires the specified model property to be an enum type.");

			//initialize values
			var metaData = ModelMetadata.FromLambdaExpression(forExpression, htmlHelper.ViewData);
			var propertyName = metaData.PropertyName;
			var propertyValue = (htmlHelper.ViewData.Eval(propertyName) ?? metaData.Model).ToStringOrEmpty();
			var name = ExpressionHelper.GetExpressionText(forExpression);
			var templateInfo = htmlHelper.ViewContext.ViewData.TemplateInfo;
			var fullHtmlFieldName = templateInfo.GetFullHtmlFieldName(name);
			var fullHtmlFieldId = templateInfo.GetFullHtmlFieldId(fullHtmlFieldName);

			var tag = new TagBuilder("select");
			tag.Attributes.Add("id", fullHtmlFieldId);
			tag.Attributes.Add("name", fullHtmlFieldName);
			
			if (htmlAttributes != null)
			{
				foreach (var kvp in htmlAttributes.GetType().GetProperties()
					.ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
				{
					tag.Attributes.Add(kvp.Key, kvp.Value.ToStringOrEmpty());

				}
			}

			var options = new StringBuilder();
			if (blankFirstLine)
			{
				var blank = new TagBuilder("option");
				blank.Attributes.Add("value", string.Empty);
			}

			//build the options tags
			foreach (var enumName in Enum.GetNames(typeof(TProperty)))
			{
				//var idValue = ((int)Enum.Parse(typeof(TProperty), enumName, true)).ToString();
				var displayValue = enumName;

				// get the corresponding enum field using reflection
				var field = typeof(TProperty).GetField(enumName);
				var display = ((DisplayAttribute[])field.GetCustomAttributes(typeof(DisplayAttribute), false)).FirstOrDefault();
				var titleValue = string.Empty;
				if (display != null)
				{
					// The enum field is decorated with the DisplayAttribute =>
					// use its value
					displayValue = display.Name;
					titleValue = display.Description.ToStringOrEmpty();
				}

				var option = new TagBuilder("option");
				option.Attributes.Add("value", enumName);
				option.Attributes.Add("title", titleValue);
				if (enumName == propertyValue)
				{
					option.Attributes.Add("selected", "selected");
				}
				option.SetInnerText(displayValue);
				options.Append(option.ToString());
			}

			tag.InnerHtml = options.ToString();
			return new HtmlString(tag.ToString());
		}

		public static HtmlString EnumSelectListFor<TModel, TProperty>(
			this HtmlHelper<TModel> htmlHelper,
			Expression<Func<TModel, TProperty>> forExpression)
			where TModel : class
			where TProperty : struct
		{
			return htmlHelper.EnumSelectListFor(forExpression, null, false);
		}
	}
}
